#include "LogicEdit.h"

LogicEdit& LogicEdit::getInstance() {
	if (_logicEdit == NULL) {
		_logicEdit = new LogicEdit;
	}

	return *_logicEdit;
}

Display LogicEdit::editTaskByName( string taskName, int index ) {

	int taskID;
	string oldTaskName;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	vector<Task> display;
	bool outOfBounds;
	stringstream displayMsg;

	outOfBounds = isOutOfBounds(index, _display.getDisplaySize());

	display = _display.getTaskList();

	if( outOfBounds ) {
		displayMsg << INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE;
	} else {
		// find task on display
		taskID = display[index-1].getTaskID();

		// if no changes made
		if( display[index-1].getTaskName() == taskName ) {
			displayMsg << NO_CHANGES_ERROR_MESSAGE;
		} else {
			oldTaskName = display[index-1].getTaskName();
			// update display
			display[index-1].setTaskName(taskName);
			// set editted task attributes
			_task = display[index-1];

			// update internal data
			dataFeedback = _data->executeEdit(_task);
		
			_data->getAll(tasks);
			_writer->write(tasks);

			displayMsg << EDIT_RENAME;
			displayMsg << FROM_CONNECTOR << oldTaskName;
			displayMsg << TO_CONNECTOR << taskName;
		}
	}

	_display = Display( displayMsg.str(), display );

	return _display;
}

Display LogicEdit::editTaskByStartTime( time_duration startTime, int index ) {

	int taskID;
	string taskName;
	time_duration oldTime;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	vector<Task> display;
	bool outOfBounds;
	stringstream displayMsg;

	outOfBounds = isOutOfBounds(index, _display.getDisplaySize());

	display = _display.getTaskList();

	if( outOfBounds ) {
		displayMsg << INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE;
	} else {
		// find task on display
		taskID = display[index-1].getTaskID();

		if( display[index-1].getStartDateTime().time_of_day() == startTime ) {
			displayMsg << NO_CHANGES_ERROR_MESSAGE;
		} else {
			_task = display[index-1];
			taskName = _task.getTaskName();
			oldTime = _task.getStartDateTime().time_of_day();
			// update display
			display[index-1].setStartTime(startTime);
			// set editted task attributes
			_task = display[index-1];

			// update internal data
			dataFeedback = _data->executeEdit(_task);

			_data->getAll(tasks);
			_writer->write(tasks);

			displayMsg << EDIT_SUCCESS_MESSAGE;
			displayMsg << taskName << EDIT_START_TIME;
			displayMsg << FROM_CONNECTOR << oldTime;
			displayMsg << TO_CONNECTOR << startTime;
		}
	}

	_display = Display( displayMsg.str(), display );

	return _display;
}

Display LogicEdit::editTaskByEndTime( time_duration endTime, int index ) {

	int taskID;
	string taskName;
	time_duration oldTime;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	vector<Task> display;
	bool outOfBounds;
	stringstream displayMsg;

	outOfBounds = isOutOfBounds(index, _display.getDisplaySize());

	display = _display.getTaskList();

	if( outOfBounds ) {
		displayMsg << INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE;
	} else {
		// find task on display
		taskID = display[index-1].getTaskID();

		if( display[index-1].getEndDateTime().time_of_day() == endTime ) {
			displayMsg << NO_CHANGES_ERROR_MESSAGE;
		} else {
			_task = display[index-1];
			oldTime = _task.getEndDateTime().time_of_day();
			taskName = _task.getTaskName();
			// set editted task attributes
			display[index-1].setEndTime(endTime);
			_task = display[index-1];

			// update internal data
			dataFeedback = _data->executeEdit(_task);

			_data->getAll(tasks);
			_writer->write(tasks);

			displayMsg << EDIT_SUCCESS_MESSAGE;
			displayMsg << taskName << EDIT_END_TIME;
			displayMsg << FROM_CONNECTOR << oldTime;
			displayMsg << TO_CONNECTOR << endTime;
		}
	}

	_display = Display( displayMsg.str(), display );

	return _display;
}

Display LogicEdit::editTaskByStartDateTime( ptime startDate, int index ) {
	
	int taskID;
	string taskName;
	ptime oldDate;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	vector<Task> display;
	bool outOfBounds;
	stringstream displayMsg;

	outOfBounds = isOutOfBounds(index, _display.getDisplaySize());

	display = _display.getTaskList();

	if( outOfBounds ) {
		displayMsg << INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE;
	} else {
		// find task on display
		taskID = display[index-1].getTaskID();

		if( display[index-1].getStartDateTime() == startDate ) {
			displayMsg << NO_CHANGES_ERROR_MESSAGE ;
		} else {
			_task = display[index-1];
			taskName = _task.getTaskName();
			oldDate = _task.getStartDateTime();
			// set editted task attributes
			display[index-1].setStartDateTime(startDate);
			_task = display[index-1];

			// update internal data
			dataFeedback = _data->executeEdit(_task);

			_data->getAll(tasks);
			_writer->write(tasks);

			displayMsg << EDIT_SUCCESS_MESSAGE;
			displayMsg << taskName << EDIT_START_DATE;
			displayMsg << FROM_CONNECTOR << oldDate;
			displayMsg << TO_CONNECTOR << startDate;
		}
	}

	_display = Display( displayMsg.str(), display );

	return _display;
}

Display LogicEdit::editTaskByEndDateTime( ptime endDate, int index ) {

	int taskID;
	string taskName;
	ptime oldDate;
	Data::DataFeedback dataFeedback;
	vector<Task> tasks;
	vector<Task> display;
	bool outOfBounds;
	stringstream displayMsg;

	outOfBounds = isOutOfBounds(index, _display.getDisplaySize());

	display = _display.getTaskList();

	if( outOfBounds ) {
		displayMsg << INDEX_OUT_OF_BOUNDS_ERROR_MESSAGE;
	} else {
		// find task on display
		taskID = display[index-1].getTaskID();

		if( display[index-1].getEndDateTime() == endDate ) {
			displayMsg << NO_CHANGES_ERROR_MESSAGE;
		} else {
			_task = display[index-1];
			taskName = _task.getTaskName();
			oldDate = _task.getEndDateTime();
			// set editted task attributes
			display[index-1].setEndDateTime(endDate);
			_task = display[index-1];

			// update internal data
			dataFeedback = _data->executeEdit(_task);

			_data->getAll(tasks);
			_writer->write(tasks);

			displayMsg << EDIT_SUCCESS_MESSAGE;
			displayMsg << taskName << EDIT_END_DATE;
			displayMsg << FROM_CONNECTOR << oldDate;
			displayMsg << TO_CONNECTOR << endDate;
		}
	}

	_display = Display( displayMsg.str(), display );

	return _display;
}

const string LogicEdit::EDIT_SUCCESS_MESSAGE = "Task Edited: ";

const string LogicEdit::EDIT_RENAME = "Task Renamed: ";
const string LogicEdit::EDIT_START_TIME = "Start Time: ";
const string LogicEdit::EDIT_END_TIME = "End Time: ";
const string LogicEdit::EDIT_START_DATE = "Start Date: ";
const string LogicEdit::EDIT_END_DATE = "End Date: ";

const string LogicEdit::FROM_CONNECTOR = " From: ";
const string LogicEdit::TO_CONNECTOR = " To: ";

const string LogicEdit::EDIT_ERROR_MESSAGE = "Unable to Edit";

const string LogicEdit::NO_CHANGES_ERROR_MESSAGE = "No Changes Made";

LogicEdit* LogicEdit::_logicEdit = NULL;